import {
    Mesh, MeshLambertMaterial, BoxGeometry, CylinderGeometry
} from 'three';

export default class HisChart {
    public group: Mesh;
    private offset: number;
    private separation: boolean;
    private cylinder: boolean;
    private heap: boolean;


    constructor(data: any[] = [], perWidth: number, manifest: Manifest) {
        const { separation = false, cylinder = false, heap = false } = manifest;
        this.offset = perWidth;
        this.group = new Mesh();
        this.separation = separation;
        this.heap = heap;
        this.cylinder = cylinder;
        data.forEach((item, i) => {
            const group = new Mesh();
            const sumHeight = this.getSumHeight(item);
            item.forEach((cur: HisChartData, index: number) => {
                const cube = this.drawCube(cur, sumHeight[index], index);
                group.add(cube)
            });
            if (this.heap) {
                group.position.x += (this.offset * 2 * i);
            } else {
                group.position.x += (this.offset * i * (item.length + 1));
            }
            this.group.add(group);
        })
        this.group.position.z = 1.5;
    }

    private drawCube(data: HisChartData, beforeHeight: number, index: number) {
        const { perHeight, perWidth, color } = data;
        let geometry;
        if (this.cylinder) {
            geometry = new CylinderGeometry(perWidth / 2, perWidth / 2, perHeight, 100)
        } else {
            geometry = new BoxGeometry(perWidth, perHeight, perWidth);
        }
        const material = new MeshLambertMaterial({ color });
        const cube = new Mesh(geometry, material);
        if (index && this.heap) {
            cube.position.y += perHeight / 2 + beforeHeight;
        } else {
            cube.position.y += perHeight / 2;
            cube.position.x += perWidth * index;
        }
        if (index && this.separation && this.heap) {
            cube.position.y += perWidth / 4;
        }
        cube.position.z -= perWidth / 2;
        return cube
    }

    private getSumHeight(data: HisChartData[]) {
        const hArr = data.map((item: HisChartData) => item.perHeight);
        const rotationY = hArr.reduce((acc: number[], cur, index) => {
            if (index === 0) {
                acc.push(cur);
            } else {
                let height = cur + acc[index - 1];
                if (this.separation) {
                    height += this.offset / 4;
                }
                acc.push(height);
            }
            return acc;
        }, [])
        rotationY.pop();
        rotationY.unshift(0);
        return rotationY;
    }
}
